package com.dalonedrow.engine.ui.base;

import com.dalonedrow.engine.sprite.base.SimpleDimension;
import com.dalonedrow.engine.sprite.base.SimpleVector2;
import com.dalonedrow.engine.sprite.base.SimpleVector3;
import com.dalonedrow.engine.sprite.base.SpriteBase;
import com.dalonedrow.engine.systems.Render;
import com.dalonedrow.engine.ui.base.border.GuiBorder;
import com.dalonedrow.globalvariables.constants.hq.GlobalConstants;
import com.dalonedrow.utils.UtilityMethods;

/**
 * @author Donald
 */
public abstract class GuiComponentImpl implements GuiComponent {
	/** flag indicating whether the {@link GuiComponent} is active. */
	private boolean		active				= true;
	/**
	 * the image displayed when the component is inactive.
	 */
	private int			activeImage			= -1;
	/** the {@link GuiComponent}'s {@link GuiBorder}. */
	private GuiBorder	border;
	/** flag for displaying debuging output. */
	private boolean		debug				= false;
	/** the component's horizontal alignment. */
	private int			horizontalAlignment	= GuiComponent.CENTER;
	/**
	 * the image displayed when the component is inactive.
	 */
	private int			inactiveImage		= -1;
	/** the {@link GuiComponent}'s {@link Insets}s. */
	private SimpleInsets		insets				= new SimpleInsets(0, 0, 0, 0);
	/** the {@link GuiComponent}'s position on screen. */
	private SimpleVector3		position;
	/**
	 * the {@link Sprite} associated with this <code>GuiComponentImpl</code>.
	 */
	private SpriteBase	sprite;
	/** the tooltip displayed. */
	private String		tooltipText;
	/** the time the user hovered over the item. */
	private long		tooltipTimer;
	/** singleton instance of local variable used in multiple locations. */
	private SimpleVector3		v					= new SimpleVector3();
	/** the component's vertical alignment. */
	private int			verticalAlignment	= GuiComponent.CENTER;
	/** the {@link View} the {@link GuiComponent} is part of. */
	private View		view;
	/** flag indicating whether the {@link GuiComponent} is visible. */
	private boolean		visible				= true;
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean contains(final double x, final double y) {
		boolean isInside = false;
		if (isVisible()) {
			if (position.getX() <= x
					&& x <= position.getX() + getPreferredSize().width
					&& position.getY() <= y
					&& y <= position.getY() + getPreferredSize().height) {
				isInside = true;
			}
		}
		return isInside;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean contains(final int x, final int y) {
		return contains((double) x, (double) y);
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean contains(final SimpleVector2 pt) {
		return contains(pt.getX(), pt.getX());
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final GuiBorder getBorder() {
		return border;
	}
	/**
	 * Gets the horizontal alignment.
	 * @return int
	 */
	public final int getHorizontalAlignment() {
		return horizontalAlignment;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public SimpleInsets getInsets() {
		return insets;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final SimpleVector3 getPosition() {
		return position;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public SimpleDimension getPreferredSizeWhenDisplayingTooltip() {
		return getPreferredSize();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public SimpleVector3 getPreferredTooltipPosition() {
		return position;
	}
	/**
	 * Gets the sprite.
	 * @return {@link SpriteBase}
	 */
	public final SpriteBase getSprite() {
		return sprite;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final String getTooltipText() {
		return tooltipText;
	}
	/**
	 * Gets the horizontal alignment.
	 * @return int
	 */
	public final int getVerticalAlignment() {
		return verticalAlignment;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final View getView() {
		return view;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean hasTooltipText() {
		return tooltipText != null && tooltipText.length() > 0;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean hasTooltipTimerStarted() {
		return tooltipTimer > 0L;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean isActive() {
		return active;
	}
	/**
	 * Gets the debugging output flag.
	 * @return <code>boolean</code>
	 */
	@Override
	public final boolean isDebug() {
		return debug;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final boolean isVisible() {
		boolean isVisible = visible;
		if (position == null) {
			isVisible = false;
		}
		return isVisible;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void prepareForRendering() throws Exception {
		if (isVisible()
				&& position != null) {
			if (border != null) {
				border.prepareForRendering();
			}
			if (sprite != null) {
				Render.getInstance().registerEntity(sprite);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setActive(final boolean isActive) {
		active = isActive;
		if (sprite != null
				&& inactiveImage > -1) {
			if (activeImage == -1) {
				// set active image
				activeImage = sprite.getImageRefId();
			}
			if (active) {
				sprite.setImageRefId(activeImage);
			} else {
				sprite.setImageRefId(inactiveImage);
			}
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setActiveImage(final int refId) {
		activeImage = refId;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setBorder(final GuiBorder newBorder) {
		border = newBorder;
		if (position != null
				&& border != null) {
			border.setPosition(
					position.getX(), position.getY(), position.getZ());
		}
	}
	/**
	 * Sets the debugging output flag.
	 * @param val the flag to set
	 */
	public void setDebug(boolean val) {
		debug = val;
	}
	/**
	 * Sets the horizontal alignment.
	 * @param val the alignment to set
	 */
	public final void setHorizontalAlignment(final int val) {
		horizontalAlignment = val;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setInactiveImage(final int refId) {
		inactiveImage = refId;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setInsets(final SimpleInsets newInsets) {
		if (newInsets == null) {
			insets = new SimpleInsets(0, 0, 0, 0);
		} else {
			insets = newInsets;
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setInsets(final int... newInsets) {
		if (newInsets == null) {
			insets = new SimpleInsets(0, 0, 0, 0);
		} else {
			final int three = 3;
			setInsets(
					newInsets[0], newInsets[1],
					newInsets[2], newInsets[three]);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setInsets(final int top, final int left,
			final int bottom,
			final int right) {
		if (insets == null) {
			insets = new SimpleInsets(top, left, bottom, right);
		} else {
			insets.set(top, left, bottom, right);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setPosition(final double x, final double y, final double z) {
		if (position == null) {
			position = new SimpleVector3(x, y, z);
		} else {
			position.set(x, y, z);
		}
		v.set(position);
		if (border != null) {
			if (v != null) {
				border.setPosition(v.getX(), v.getY(), v.getZ());
			}
			v.move(
					border.getInsets().left,
					border.getInsets().bottom,
					0d
					);
		}
		if (sprite != null) {
			if (insets != null) {
				v.move(insets.left, insets.bottom, 0d);
			}
			sprite.setPosition(v.getX(), v.getY(), v.getZ()
					+ GlobalConstants.CHILD_STEP * 0.01d);
		}
	}
	public void setPositionExcludingBorders(final double x, final double y,
			final double z) {
		if (position == null) {
			position = new SimpleVector3(x, y, z);
		} else {
			position.set(x, y, z);
		}
		v.set(position);
		if (border != null) {
			v.move(
					border.getInsets().left,
					border.getInsets().bottom,
					0d
					);
		}
		if (sprite != null) {
			if (insets != null) {
				v.move(insets.left, insets.bottom, 0d);
			}
			sprite.setPosition(v.getX(), v.getY(), v.getZ());
		}
	}
	/**
	 * Sets the sprite.
	 * @param newSprite the {@link Sprite} to set
	 */
	public final void setSprite(final SpriteBase newSprite) {
		sprite = newSprite;
		if (position != null) {
			v.set(position);
			if (border != null) {
				v.move(
						border.getInsets().left,
						border.getInsets().bottom,
						0d
						);
			}
			if (insets != null) {
				v.move(insets.left, insets.bottom, 0d);
			}
			sprite.setPosition(v.getX(), v.getY(), v.getZ()
					+ GlobalConstants.CHILD_STEP * 0.01d);
		}
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setTooltipText(float newText) {
		setTooltipText(Float.toString(newText));
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void setTooltipText(int newText) {
		setTooltipText(Integer.toString(newText));
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setTooltipText(final String newText) {
		tooltipText = newText;
	}
	/**
	 * Sets the vertical alignment.
	 * @param val the alignment to set
	 */
	public final void setVerticalAlignment(final int val) {
		verticalAlignment = val;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void setView(final View newView) {
		view = newView;
	}
	/**
	 * {@inheritDoc}
	 */
	/*
	 * @Override public void update(final long time) { if (sprite != null) {
	 * sprite.update(time); } }
	 */
	/**
	 * Sets the visible
	 * @param visible the visible to set
	 */
	@Override
	public void setVisible(final boolean flag) {
		visible = flag;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void startTooltipTimer(final long time) {
		tooltipTimer = time;
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public final void stopTooltipTimer() {
		tooltipTimer = 0L;
		ToolTip.getInstance().stop();
	}
	/**
	 * {@inheritDoc}
	 */
	@Override
	public void updateTooltipTimer(final long time) {
		if (hasTooltipText() && hasTooltipTimerStarted()) {
			long now = tooltipTimer
					+ UtilityMethods.getInstance().convertMilliToNano(
							GlobalConstants.TOOLTIP_DELAY);
			if (time >= now) {
				if (!ToolTip.getInstance().isVisible()) {
					ToolTip.getInstance().setText(tooltipText);
					ToolTip.getInstance().start(this);
				}
			} else if (ToolTip.getInstance().isVisible()) {
				// tooltip is visible, but the component that is being timed
				// isnt ready to display. stop the tooltip
				ToolTip.getInstance().stop();
			}
		}
	}
}
